package com.itheima.stock.service.impl;

import com.fasterxml.jackson.databind.json.JsonMapper;
import com.google.common.collect.Lists;
import com.itheima.stock.mapper.*;
import com.itheima.stock.pojo.entity.*;
import com.itheima.stock.pojo.vo.StockInfoConfig;
import com.itheima.stock.service.StockTimeTaskService;
import com.itheima.stock.utils.DateTimeUtil;
import com.itheima.stock.utils.IdWorker;
import com.itheima.stock.utils.ParseType;
import com.itheima.stock.utils.ParserStockInfoUtil;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.A;
import org.joda.time.DateTime;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.PostConstruct;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;


@Service
@Slf4j
public class StockTimeTaskServiceImpl implements StockTimeTaskService {
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private StockInfoConfig stockInfoConfig;
    @Autowired
    private IdWorker idWorker;
    @Autowired
    private StockMarketIndexInfoMapper stockMarketIndexInfoMapper;
    @Autowired
    private StockBusinessMapper stockBusinessMapper;
    @Autowired
    private StockRtInfoMapper stockRtInfoMapper;
    @Autowired
    private StockBlockRtInfoMapper stockBlockRtInfoMapper;
    @Autowired
    private StockOuterMarketIndexInfoMapper stockOuterMarketIndexInfoMapper;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    private HttpEntity<Object> httpEntity;
    @Autowired
    private ParserStockInfoUtil parserStockInfoUtil;


    //1.国内大盘上-深
    @Override
    public void getInnerMarketInfo() {
        //1.采集数据
        String URL = stockInfoConfig.getMarketUrl() + String.join(",", stockInfoConfig.getInner());
        ResponseEntity<String> responseEntity = restTemplate.exchange(URL, HttpMethod.GET, httpEntity, String.class);
        int statusCodeValue = responseEntity.getStatusCodeValue();
        if (statusCodeValue != 200) {
            log.error("当前时间点失败:{},状态码:{}", DateTime.now().toString("yyyy-MM-dd HH:mm:ss"), statusCodeValue);
            return;
        }
        String jsData = responseEntity.getBody();
        log.info("当前时间点成功:{},采集内容:{}", DateTime.now().toString("yyyy-MM-dd HH:mm:ss"), jsData);

        //2、正则解析
        String reg = "var hq_str_(.+)=\"(.+)\";";
        //校验
        Pattern pattern = Pattern.compile(reg);
        Matcher matcher = pattern.matcher(jsData);
        List<StockMarketIndexInfo> entitys = new ArrayList<>();
        //3、实体封装数据
        while (matcher.find()) {
            String marketCode = matcher.group(1);
            String otherInfo = matcher.group(2);
            String[] splitArr = otherInfo.split(",");
            //大盘名称
            String marketName = splitArr[0];
            //获取当前大盘的开盘点数
            BigDecimal openPoint = new BigDecimal(splitArr[1]);
            //前收盘点
            BigDecimal preClosePoint = new BigDecimal(splitArr[2]);
            //获取大盘的当前点数
            BigDecimal curPoint = new BigDecimal(splitArr[3]);
            //获取大盘最高点
            BigDecimal maxPoint = new BigDecimal(splitArr[4]);
            //获取大盘的最低点
            BigDecimal minPoint = new BigDecimal(splitArr[5]);
            //获取成交量
            Long tradeAmt = Long.valueOf(splitArr[8]);
            //获取成交金额
            BigDecimal tradeVol = new BigDecimal(splitArr[9]);
            Date curTime = DateTimeUtil.getDateTimeWithoutSecond(splitArr[30] + " " + splitArr[31]).toDate();

            StockMarketIndexInfo entity = StockMarketIndexInfo.builder()
                    .id(idWorker.nextId())
                    .marketCode(marketCode)
                    .marketName(marketName)
                    .openPoint(openPoint)
                    .preClosePoint(preClosePoint)
                    .curPoint(curPoint)
                    .maxPoint(maxPoint)
                    .minPoint(minPoint)
                    .tradeAmount(tradeAmt)
                    .tradeVolume(tradeVol)
                    .curTime(curTime)
                    .build();
            entitys.add(entity);
            System.out.println(entitys);
        }
        //4、保存数据库
        int count = stockMarketIndexInfoMapper.insertbacth(entitys);
        if (count > 0) {
            rabbitTemplate.convertAndSend("stockExchange","inner.market",new Date());
            log.info("时间:{},插入大盘:{}", DateTime.now().toString("yyyy-MM-dd HH:mm:ss"), entitys);
            return;
        }

        log.error("失败时间:{},插入大盘:{}", DateTime.now().toString("yyyy-MM-dd HH:mm:ss"), entitys);
    }


    //2.获取实时个股分钟股票
    @Override
    public void getStockRtInfo() {

        List<String> allCodes = stockBusinessMapper.getAllStockBusiness();
        allCodes = allCodes.stream().map(code -> code.startsWith("6") ? "sh" + code : "sz" + code).collect(Collectors.toList());
        Lists.partition(allCodes, 15).forEach(codes -> {

//            String url = stockInfoConfig.getMarketUrl() + String.join(",", codes);
//            ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class);
//            int statusCodeValue = responseEntity.getStatusCodeValue();
//            if (statusCodeValue != 200) {
//                log.error("当前时间点失败:{},状态码:{}", DateTime.now().toString("yyyy-MM-dd HH:mm:ss"), statusCodeValue);
//                return;
//            }
//            String jsData = responseEntity.getBody();
//            List<StockRtInfo> list = parserStockInfoUtil.parser4StockOrMarketInfo(jsData, ParseType.ASHARE);
//            log.info("list大盘:{}", list);
//            //4、保存数据库
//            int count = stockRtInfoMapper.insertbacth(list);
//            if (count > 0) {
//                log.info("时间:{},插入个股:{}", DateTime.now().toString("yyyy-MM-dd HH:mm:ss"), list);
//                return;
//            }
//
//            log.error("失败时间:{},插入个股:{}", DateTime.now().toString("yyyy-MM-dd HH:mm:ss"), list);

        //1.串行效率低
//            new Thread(()->{
//                String url = stockInfoConfig.getMarketUrl() + String.join(",", codes);
//                ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class);
//                int statusCodeValue = responseEntity.getStatusCodeValue();
//                if (statusCodeValue != 200) {
//                    log.error("当前时间点失败:{},状态码:{}", DateTime.now().toString("yyyy-MM-dd HH:mm:ss"), statusCodeValue);
//                    return;
//                }
//                String jsData = responseEntity.getBody();
//                List<StockRtInfo> list = parserStockInfoUtil.parser4StockOrMarketInfo(jsData, ParseType.ASHARE);
//                log.info("list大盘:{}", list);
//                //4、保存数据库
//                int count = stockRtInfoMapper.insertbacth(list);
//                if (count > 0) {
//                    log.info("时间:{},插入个股:{}", DateTime.now().toString("yyyy-MM-dd HH:mm:ss"), list);
//                    return;
//                }
//
//                log.error("失败时间:{},插入个股:{}", DateTime.now().toString("yyyy-MM-dd HH:mm:ss"), list);
//
//            }).start();

            //线程池
        threadPoolTaskExecutor.execute(()->{
            String url = stockInfoConfig.getMarketUrl() + String.join(",", codes);
            ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class);
            int statusCodeValue = responseEntity.getStatusCodeValue();
            if (statusCodeValue != 200) {
                log.error("当前时间点失败:{},状态码:{}", DateTime.now().toString("yyyy-MM-dd HH:mm:ss"), statusCodeValue);
                return;
            }
            String jsData = responseEntity.getBody();
            List<StockRtInfo> list = parserStockInfoUtil.parser4StockOrMarketInfo(jsData, ParseType.ASHARE);
            log.info("list:{}", list);
            //4、保存数据库
            int count = stockRtInfoMapper.insertbacth(list);
            if (count > 0) {
                log.info("时间:{},插入个股:{}", DateTime.now().toString("yyyy-MM-dd HH:mm:ss"), list);
                return;
            }
            log.error("失败时间:{},插入个股:{}", DateTime.now().toString("yyyy-MM-dd HH:mm:ss"), list);
        });

        });
    }
    //4、获取外盘盘股
    @Override
    public void getStock_outer_market_index_info(){
        List<String> outers = stockInfoConfig.getOuter();
        outers = outers.stream().collect(Collectors.toList());
        Lists.partition(outers,3).forEach(outer->{
            threadPoolTaskExecutor.execute(()->{
                String url = stockInfoConfig.getMarketUrl()+ String.join(",", outer);
                ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class);
                int statusCodeValue = responseEntity.getStatusCodeValue();
                if (statusCodeValue != 200) {
                    log.error("当前时间点失败:{},状态码:{}", DateTime.now().toString("yyyy-MM-dd HH:mm:ss"), statusCodeValue);
                    return;
                }
                              String jsData = responseEntity.getBody();
                List<StockOuterMarketIndexInfo> outs = parserStockInfoUtil.parser4StockOrMarketInfo(jsData,ParseType.OUTER);
             int count=   stockOuterMarketIndexInfoMapper.insertBatch(outs);
             if (count > 0) {
                 System.out.println(count);
             }else {
                 System.out.println("插入失败");
             }
            });
        });

    }


    //3.获取板块
    @Override
    public void getStockBlock() {
        String url = stockInfoConfig.getBlockUrl();
        String result = restTemplate.getForObject(url, String.class);

        List<StockBlockRtInfo> blockRtInfos = parserStockInfoUtil.parse4StockBlock(result);
       Lists.partition(blockRtInfos,10).forEach((list)->{
           threadPoolTaskExecutor.execute(()->{
               int count= stockBlockRtInfoMapper.insertBlock(blockRtInfos);
               if (count > 0) {
                   System.out.println("插入"+count+"条数据");
               }
           });
       });


    }


    @PostConstruct
    public void initData() {
        HttpHeaders headers = new HttpHeaders();
        headers.add("Referer", "https://finance.sina.com.cn/stock/");
        headers.add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.6261.95 Safari/537.36");
        httpEntity = new HttpEntity<>(headers);
    }

}
